/*!
 * RENEWTEK IMPORTANT NOTES: THESE CODE HAVE BEEN MODIFIED, PLEASE DON'T TRY TO REPLACE WITH NEWEST VERSION OF THIS COMPONENT.
 *
 * FullCalendar v1.2.1
 * http://arshaw.com/fullcalendar/
 *
 * use fullcalendar.css for basic styling
 * requires jQuery UI core and draggables ONLY if you plan to do drag & drop
 *
 * Copyright (c) 2009 Adam Shaw
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Date: 2009-05-31 13:56:02 -0700 (Sun, 31 May 2009)
 * Revision: 23
 */

(function($) {

   $.fn.fullCalendar = function(options) {


      //
      // Calls methods on a pre-existing instance
      //

      if (typeof options == 'string') {
         var args = Array.prototype.slice.call(arguments, 1);
         var res;
         this.each(function() {
            var r = $.data(this, 'fullCalendar')[options].apply(this, args);
            if (typeof res == 'undefined') {
               res = r;
            }
         });
         if (typeof res != 'undefined') {
            return res;
         }
         return this;
      }


      //
      // Process options
      //

      options = options || {};

      var r2l = options.rightToLeft;
      var dis, dit; // day index sign / translate
      if (r2l) {
         dis = -1;
         dit = 6;
         this.addClass('r2l');
      } else {
         dis = 1;
         dit = 0;
      }

      var showTime = typeof options.showTime == 'undefined' ? 'guess' : options.showTime;
      var bo = typeof options.buttons == 'undefined' ? true : options.buttons;
      var weekStart = (options.weekStart || 0) % 7;
      var timeFormat = options.timeFormat || 'gx';
      var titleFormat = options.titleFormat || (r2l ? 'Y F' : 'F Y');


      //
      // Rendering bug detection variables
      //

      var tdTopBug, trTopBug, tbodyTopBug, sniffBugs = true;


      this.each(function() {


         //
         // Instance variables
         //

         var date = options.year ? // holds the year & month of current month
                 new Date(options.year, options.month || 0, 1) :
                 new Date();
         var start, end; // first & last VISIBLE dates
         var today;
         var numWeeks;
         var ignoreResizes = false;

         var events = [];
         var eventSources = options.eventSources || [];
         if (options.events) {
            eventSources.push(options.events);
         }


         //
         // Month navigation functions
         //
         // PHUC CODE CHANGE: ADD Function clearHolidayElements();
         function refreshMonth() {
            clearEventElements();
            clearHolidayElements();
            render();
         }

         function prevMonth() {
            addMonths(date, -1);
            refreshMonth();
         }

         function nextMonth() {
            addMonths(date, 1);
            refreshMonth();
         }

         function gotoToday() {
            date = new Date();
            refreshMonth();
         }

         function gotoMonth(year, month) {
            date = new Date(year, month, 1);
            refreshMonth();
         }

         function prevYear() {
            addYears(date, -1);
            refreshMonth();
         }

         function nextYear() {
            addYears(date, 1);
            refreshMonth();
         }


         //
         // Publicly accessible methods
         //

         $.data(this, 'fullCalendar', {
            refresh: refreshMonth,
            prevMonth: prevMonth,
            nextMonth: nextMonth,
            today: gotoToday,
            gotoMonth: gotoMonth,
            prevYear: prevYear,
            nextYear: nextYear,


            //
            // Event CRUD
            //

            addEvent: function(event) {
               events.push(normalizeEvent(event));
               clearEventElements();
               renderEvents();
            },

            updateEvent: function(event) {
               event.start = $.fullCalendar.parseDate(event.start);
               event.end = $.fullCalendar.parseDate(event.end);
               var startDelta = event.start - event._start;
               var msLength = event.end - event.start;
               event._start = cloneDate(event.start);
               for (var i = 0; i < events.length; i++) {
                  var e = events[i];
                  if (e.id === event.id && e !== event) {
                     e.start = new Date(e.start.getTime() + startDelta);
                     e._start = cloneDate(e.start);
                     e.end = new Date(e.start.getTime() + msLength);
                     for (var k in event) {
                        if (k && k != 'start' && k != 'end' && k.charAt(0) != '_') {
                           e[k] = event[k];
                        }
                     }
                  }
               }
               clearEventElements();
               renderEvents();
            },

            removeEvent: function(eventId) {
               if (typeof eventId == 'object') {
                  eventId = eventId.id;
               }

               // remove from the 'events' array
               var newEvents = [];
               for (var i = 0; i < events.length; i++) {
                  if (events[i].id !== eventId) {
                     newEvents.push(events[i]);
                  }
               }
               events = newEvents;

               // remove from static event sources
               for (var i = 0; i < eventSources.length; i++) {
                  var src = eventSources[i];
                  if (typeof src != 'string' && !$.isFunction(src)) {
                     var newSrc = [];
                     for (var j = 0; j < src.length; j++) {
                        if (src[j].id !== eventId) {
                           newSrc.push(src[j]);
                        }
                     }
                     eventSources[i] = newSrc;
                  }
               }

               clearEventElements();
               renderEvents();
            },

            getEventsById: function(eventId) {
               var res = [];
               for (var i = 0; i < events.length; i++) {
                  if (events[i].id === eventId) {
                     res.push(events[i]);
                  }
               }
               return res;
            },



            //
            // Event Source CRUD
            //

            addEventSource: function(src) {
               eventSources.push(src);
               pushLoading();
               fetchEventSource(src, function() {
                  popLoading();
                  clearEventElements();
                  renderEvents();
               });
            },

            removeEventSource: function(src) {

               // remove from 'eventSources' array
               var newSources = [];
               for (var i = 0; i < eventSources.length; i++) {
                  if (src !== eventSources[i]) {
                     newSources.push(eventSources[i]);
                  }
               }
               eventSources = newSources;

               // remove events from 'events' array
               var newEvents = [];
               for (var i = 0; i < events.length; i++) {
                  if (events[i].source !== src) {
                     newEvents.push(events[i]);
                  }
               }
               events = newEvents;

               clearEventElements();
               renderEvents();
            }

         });


         /*******************************************************************/
         //
         //    Header & Table Rendering
         //
         /*******************************************************************/


         //
         // Build one-time DOM elements (header, month container)
         //

         var titleElement, todayButton, monthElement, monthElementWidth;
         var header = $("<div class='full-calendar-header'/>").appendTo(this);

         if (bo) { // "button options"
            var buttons = $("<div class='full-calendar-buttons'/>").appendTo(header);
            if (bo == true || bo.today !== false) {
               todayButton = $("<button class='today' />")
                       .append($("<span />").html(
                       typeof bo.today == 'string' ?
                               bo.today : "today"))
                       .click(gotoToday);
               buttons.append(todayButton);
            }
            if (bo.prevYear) {
               var b = $("<button class='prev-year' />")
                       .append($("<span />")
                       .html(typeof bo.prevYear == 'string' ?
                       bo.prevYear : "&laquo;"))
                       .click(prevYear);
               if (r2l) {
                  buttons.prepend(b);
               }
               else {
                  buttons.append(b);
               }
            }
            if (bo == true || bo.prevMonth !== false) {
               var b = $("<button class='prev-month' />")
                       .append($("<span />")
                       .html(typeof bo.prevMonth == 'string' ?
                       bo.prevMonth : (r2l ? "&gt;" : "&lt;")))
                       .click(prevMonth);
               if (r2l) {
                  buttons.prepend(b);
               }
               else {
                  buttons.append(b);
               }
            }
            if (bo == true || bo.nextMonth !== false) {
               var b = $("<button class='next-month' />")
                       .append($("<span />").html(typeof bo.nextMonth == 'string' ?
                       bo.nextMonth : (r2l ? "&lt;" : "&gt;")))
                       .click(nextMonth);
               if (r2l) {
                  buttons.prepend(b);
               }
               else {
                  buttons.append(b);
               }
            }
            if (bo.nextYear) {
               var b = $("<button class='next-year' />")
                       .append($("<span />").html(typeof bo.nextYear == 'string'
                       ? bo.nextYear : "&raquo;"))
                       .click(nextYear);
               if (r2l) {
                  buttons.prepend(b);
               }
               else {
                  buttons.append(b);
               }
            }
         }

         if (options.title !== false) {
            titleElement = $("<h2 class='full-calendar-title'/>").appendTo(header);
         }

         monthElement = $("<div class='full-calendar-month' style='position:relative'/>")
                 .appendTo($("<div class='full-calendar-month-wrap'/>").appendTo(this));


         //
         // Build the TABLE cells for the current month. (calls event fetching & rendering code)
         //

         var thead, tbody, glass;

         function render() {
            ignoreResizes = true;
            date.setDate(1);
            clearTime(date);
            var year = date.getFullYear();
            var month = date.getMonth();
            var monthTitle = $.fullCalendar.formatDate(date, titleFormat);
            if (titleElement) {
               titleElement.text(monthTitle);
            }

            clearTime(date);
            start = cloneDate(date);
            addDays(start, -((start.getDay() - weekStart + 7) % 7));
            end = cloneDate(date);
            addMonths(end, 1);
            addDays(end, (7 - end.getDay() + weekStart) % 7);
            numWeeks = Math.round((end.getTime() - start.getTime()) / 604800000);
            if (options.fixedWeeks != false) {
               addDays(end, (6 - numWeeks) * 7);
               numWeeks = 6;
            }

            today = clearTime(new Date());
            if (todayButton) {
               if (today.getFullYear() == year && today.getMonth() == month) {
                  todayButton.css('visibility', 'hidden');
               } else {
                  todayButton.css('visibility', 'visible');
               }
            }

            var dayNames = $.fullCalendar.dayNames;
            var dayAbbrevs = $.fullCalendar.dayAbbrevs;

            if (!tbody) {

               // first time, build all cells from scratch

               var table = $("<table style='width:100%'/>").appendTo(monthElement);

               thead = "<thead><tr>";
               for (var i = 0; i < 7; i++) {
                  var j = (i * dis + dit + weekStart) % 7;
                  thead +=
                          "<th class='" + dayAbbrevs[j].toLowerCase() +
                                  (i == 0 ? ' first' : '') + "'>" +
                                  (options.abbrevDayHeadings != false ? dayAbbrevs[j] : dayNames[j]) +
                                  "</th>";
               }
               thead = $(thead + "</tr></thead>").appendTo(table);

               tbody = "<tbody>";
               var d = cloneDate(start);
               for (var i = 0; i < numWeeks; i++) {
                  tbody += "<tr class='week" + (i + 1) + "'>";
                  var tds = "";
                  for (var j = 0; j < 7; j++) {
                     var s =
                             "<td" +
                                // PHUC CODE CHANGE: ADD ID
                                     " id = '" + d.getTime() + "' " +
                                     " class='day " + dayAbbrevs[(j + weekStart) % 7].toLowerCase() +
                                     (j == dit ? ' first' : '') +
                                     (d.getMonth() == month ? '' : ' other-month') +
                                     (d.getTime() == today.getTime() ? ' today' : '') +
                                     (d.getDay() == 0 || d.getDay() == 6 ? ' weekend' : '') +
                                     "'><div class='day-number'>" + d.getDate() + "</div>" +
                                     "<div class='day-content'><div/></div></td>";
                     if (r2l) {
                        tds = s + tds;
                     }
                     else {
                        tds += s;
                     }
                     addDays(d, 1);
                  }
                  tbody += tds + "</tr>";
               }
               tbody = $(tbody + "</tbody>").appendTo(table);

               // a protective coating over the TABLE
               // intercepts mouse clicks and prevents text-selection
               glass = $("<div style='position:absolute;top:0;left:0;z-index:1;width:100%' />")
                       .appendTo(monthElement)
                       .click(function(ev, ui) {
                  if (options.dayClick) {
                     buildDayGrid();
                     var td = dayTD(ev.pageX, ev.pageY);
                     if (td) {
                        return options.dayClick.call(td, dayDate(td));
                     }
                  }
               });

            } else {

               // NOT first time, reuse as many cells as possible

               var diff = numWeeks - tbody.find('tr').length;
               if (diff < 0) {
                  // remove extra rows
                  tbody.find('tr:gt(' + (numWeeks - 1) + ')').remove();
               }
               else if (diff > 0) {
                  var trs = "";
                  for (var i = 0; i < diff; i++) {
                     trs += "<tr class='week" + (numWeeks + i) + "'>";
                     for (var j = 0; j < 7; j++) {
                        trs +=
                                "<td class='day " +
                                        dayAbbrevs[(j * dis + dit + weekStart) % 7].toLowerCase() +
                                        (j == 0 ? ' first' : '') + "'>" +
                                        "<div class='day-number'></div>" +
                                        "<div class='day-content'><div/></div>" +
                                        "</td>";
                     }
                     trs += "</tr>";
                  }
                  if (trs) {
                     tbody.append(trs);
                  }
               }

               // re-label and re-class existing cells
               var d = cloneDate(start);
               tbody.find('tr').each(function() {
                  for (var i = 0; i < 7; i++) {
                     var td = this.childNodes[i * dis + dit];
                     if (d.getMonth() == month) {
                        $(td).removeClass('other-month');
                     } else {
                        $(td).addClass('other-month');
                     }
                     if (d.getTime() == today.getTime()) {
                        $(td).addClass('today');
                     } else {
                        $(td).removeClass('today');
                     }
                     if (d.getDay() == 0 || d.getDay() == 6) {
                        $(td).addClass('weekend');
                     } else {
                        $(td).removeClass('weekend');
                     }
                     $(td.childNodes[0]).text(d.getDate());
                     addDays(d, 1);
                  }
               });
               // PHUC CODE CHANGE: re-id existing cells
               var date_temp = cloneDate(start);
               $('.day').each(function(index) {
                  $(this).attr("id", date_temp.getTime());
                  addDays(date_temp, 1);
               });
            }

            setCellSizes();

            if (sniffBugs) {
               // nasty bugs in opera 9.25
               // position() returning relative to direct parent
               var tr = tbody.find('tr');
               var td = tr.find('td');
               var trTop = tr.position().top;
               var tdTop = td.position().top;
               tdTopBug = tdTop < 0;
               trTopBug = trTop != tdTop;
               tbodyTopBug = tbody.position().top != trTop;
               sniffBugs = false;
            }

            fetchEvents(renderEvents);

            ignoreResizes = false;

            if (options.monthDisplay) {
               options.monthDisplay(date.getFullYear(), date.getMonth(), monthTitle);
            }

         }


         //
         // Adjust dimensions of the cells, based on container's width
         //

         function setCellSizes() {
            var tbodyw = tbody.width();
            var cellw = Math.floor(tbodyw / 7);
            var cellh = Math.round(cellw * .85);
            thead.find('th')
                    .filter(':lt(6)').width(cellw).end()
                    .filter(':eq(6)').width(tbodyw - cellw * 6);
            tbody.find('td').height(cellh);
            glass.height(monthElement.height());
            monthElementWidth = monthElement.width();
         }


         /*******************************************************************/
         //
         //    Event Rendering
         //
         /*******************************************************************/


         //
         // Render the 'events' array. First, break up into segments
         //

         var eventMatrix = [];

         function renderEvents() {
            eventMatrix = [];
            var i = 0;
            var ws = cloneDate(start);
            var we = addDays(cloneDate(ws), 7);
            while (ws.getTime() < end.getTime()) {
               var segs = [];
               $.each(events, function(j, event) {
                  if (event.end.getTime() > ws.getTime() && event.start.getTime() < we.getTime()) {
                     var ss, se, isStart, isEnd;
                     if (event.start.getTime() < ws.getTime()) {
                        ss = cloneDate(ws);
                        isStart = false;
                     } else {
                        ss = cloneDate(event.start);
                        isStart = true;
                     }
                     if (event.end.getTime() > we.getTime()) {
                        se = cloneDate(we);
                        isEnd = false;
                     } else {
                        se = cloneDate(event.end);
                        isEnd = true;
                     }
                     ss = clearTime(ss);
                     se = clearTime((se.getHours() == 0 && se.getMinutes() == 0) ? se : addDays(se, 1));
                     segs.push({
                        event: event, start: ss, end: se,
                        isStart: isStart, isEnd: isEnd, msLength: se - ss
                     });
                  }
               });
               segs.sort(segCmp);
               var levels = [];
               $.each(segs, function(j, seg) {
                  var l = 0; // level index
                  while (true) {
                     var collide = false;
                     if (levels[l]) {
                        for (var k = 0; k < levels[l].length; k++) {
                           if (seg.end.getTime() > levels[l][k].start.getTime() &&
                                   seg.start.getTime() < levels[l][k].end.getTime()) {
                              collide = true;
                              break;
                           }
                        }
                     }
                     if (collide) {
                        l++;
                        continue;
                     } else {
                        break;
                     }
                  }
                  if (levels[l]) {
                     levels[l].push(seg);
                  }
                  else {
                     levels[l] = [seg];
                  }
               });
               eventMatrix[i] = levels;
               addDays(ws, 7);
               addDays(we, 7);
               i++;
            }
            _renderEvents();
         }


         //
         // Do the REAL rendering of the segments
         //

         var eventElements = []; // [[event, element], ...]

         function _renderEvents() {
            for (var i = 0; i < eventMatrix.length; i++) {
               var levels = eventMatrix[i];
               var tr = tbody.find('tr:eq(' + i + ')');
               var td = tr.find('td:first');
               var innerDiv = td.find('div.day-content div').css('position', 'relative');
               var top = innerDiv.position().top;
               if (tdTopBug) {
                  top -= td.position().top;
               }
               if (trTopBug) {
                  top += tr.position().top;
               }
               if (tbodyTopBug) {
                  top += tbody.position().top;
               }
               var height = 0;
               for (var j = 0; j < levels.length; j++) {
                  var segs = levels[j];
                  var maxh = 0;
                  for (var k = 0; k < segs.length; k++) {
                     var seg = segs[k];
                     var event = seg.event;
                     var left1, left2, roundW, roundE;
                     if (seg.event.weekends === false) {
                        if (seg.isStart && seg.start.getDay() == 0) {
                           addDays(seg.start, 1, true);
                        }

                        if (seg.isStart && seg.start.getDay() == 6) {
                           continue;
                        }

                        if (seg.isEnd && seg.end.getDay() == 1) {
                           continue;
                        }
                     }
                     if (r2l) {
                        if (seg.event.weekends === false) {
                           left1 = seg.isEnd ?
                                   tr.find('td:eq(' + ((seg.end
                                           .getDay() + 5 - weekStart) % 7 * dis + dit) + ') div.day-content div')
                                           .position().left :
                                   tr.find('td:eq(' + ((5 - weekStart) % 7 * dis + dit) + ') div.day-content div')
                                           .position().left;
                           left2 = seg.isStart ?
                                   tr.find('td:eq(' + ((seg.start
                                           .getDay() - weekStart + 7) % 7 * dis + dit) + ') div.day-content div') :
                                   tr.find('td:eq(' + ((1 - weekStart + 7) % 7 * dis + dit) + ') div.day-content div');
                        } else {
                           left1 = seg.isEnd ?
                                   tr.find('td:eq(' + ((seg.end
                                           .getDay() + 6 - weekStart) % 7 * dis + dit) + ') div.day-content div')
                                           .position().left :
                                   tbody.position().left;
                           left2 = seg.isStart ?
                                   tr.find('td:eq(' + ((seg.start
                                           .getDay() - weekStart + 7) % 7 * dis + dit) + ') div.day-content div') :
                                   tbody;
                        }
                        roundW = seg.isEnd;
                        roundE = seg.isStart;
                     } else {
                        if (seg.event.weekends === false) {
                           left1 = seg.isStart ?
                                   tr.find('td:eq(' + ((seg.start
                                           .getDay() - weekStart + 7) % 7) + ') div.day-content div').position().left :
                                   tr.find('td:eq(' + ((1 - weekStart + 7) % 7) + ') div.day-content div').position()
                                           .left;
                           left2 = seg.isEnd ?
                                   tr.find('td:eq(' + ((seg.end
                                           .getDay() + 5 - weekStart) % 7) + ') div.day-content div') :
                                   tr.find('td:eq(' + ((seg.end
                                           .getDay() + 5 - weekStart) % 7) + ') div.day-content div');
                        } else {
                           left1 = seg.isStart ?
                                   tr.find('td:eq(' + ((seg.start
                                           .getDay() - weekStart + 7) % 7) + ') div.day-content div').position().left :
                                   tbody.position().left;
                           left2 = seg.isEnd ?
                                   tr.find('td:eq(' + ((seg.end
                                           .getDay() + 6 - weekStart) % 7) + ') div.day-content div') :
                                   tbody;
                        }
                        roundW = seg.isStart;
                        roundE = seg.isEnd;
                     }
                     left2 = left2.position().left + left2.width();
                     var cl = event.className;
                     if (typeof cl == 'string') {
                        cl = ' ' + cl;
                     }
                     else if (typeof cl == 'object') {
                        cl = ' ' + cl.join(' ');
                     }
                     // PHUC CODE CHANGE
                     var element = $("<table class='event" + (cl || '') + "' />")
                     element.append("<tr>" +
                             (roundW ? "<td class='nw'/>" : '') +
                             "<td class='n'/>" +
                             (roundE ? "<td class='ne'/>" : '') + "</tr>");

                     if (event.status == 0) {
                        element.append("<tr>" +
                                (roundW ? "<td class='w'/>" : '') +
                                "<td class='requested'/>" +
                                (roundE ? "<td class='e'/>" : '') + "</tr>");
                     }
                     else if (event.status == 1) {
                        element.append("<tr>" +
                                (roundW ? "<td class='w'/>" : '') +
                                "<td class='approved'/>" +
                                (roundE ? "<td class='e'/>" : '') + "</tr>");
                     }
                     else if (event.status == 2) {
                        element.append("<tr>" +
                                (roundW ? "<td class='w'/>" : '') +
                                "<td class='rejected'/>" +
                                (roundE ? "<td class='e'/>" : '') + "</tr>");
                     }
                     else if (event.status == -1) {
                        element.append("<tr>" +
                                (roundW ? "<td class='w'/>" : '') +
                                "<td class='holidays'/>" +
                                (roundE ? "<td class='e'/>" : '') + "</tr>");
                     }
                     else if (event.status == -2) {
                        element.append("<tr>" +
                                (roundW ? "<td class='w'/>" : '') +
                                "<td class='projects'/>" +
                                (roundE ? "<td class='e'/>" : '') + "</tr>");
                     }

                     element.append("<tr>" +
                             (roundW ? "<td class='sw'/>" : '') +
                             "<td class='s'/>" +
                             (roundE ? "<td class='se'/>" : '') + "</tr>");

                     buildEventText(event, element.find('td.requested'));
                     buildEventText(event, element.find('td.approved'));
                     buildEventText(event, element.find('td.rejected'));
                     buildEventText(event, element.find('td.holidays'));
                     buildEventText(event, element.find('td.projects'));
                     // PHUC CODE CHANGE --> END
                     if (options.eventRender) {
                        var res = options.eventRender(event, element);
                        if (typeof res != 'undefined') {
                           if (res === false) {
                              continue;
                           }
                           if (res !== true) {
                              element = $(res);
                           }
                        }
                     }
                     element
                             .css({
                                     position: 'absolute',
                                     top: top,
                                     left: left1,
                                     width: left2 - left1,
                                     'z-index': 3
                                  })
                             .appendTo(monthElement);
                     initEventElement(event, element);
                     var h = element.outerHeight({ margin: true });
                     if (h > maxh) {
                        maxh = h;
                     }
                  }
                  height += maxh;
                  top += maxh;
               }
               innerDiv.height(height);
            }
         }


         //
         // create the text-contents of an event segment
         //

         function buildEventText(event, element) {
            $("<span class='event-title' />")
                    .text(event.title)
                    .appendTo(element);
            var st = typeof event.showTime == 'undefined' ? showTime : event.showTime;
            if (st != false) {
               if (st == true || st == 'guess' &&
                       (event.start.getHours() || event.start.getMinutes() ||
                               event.end.getHours() || event.end.getMinutes())) {
                  var timeStr = $.fullCalendar.formatDate(event.start, timeFormat);
                  var timeElement = $("<span class='event-time' />");
                  if (r2l) {
                     element.append(timeElement.text(' ' + timeStr));
                  }
                  else {
                     element.prepend(timeElement.text(timeStr + ' '));
                  }
               }
            }
         }


         //
         // Attach event handlers to an event segment
         //

         function initEventElement(event, element) {
            element.click(function(ev) {
               if (!element.hasClass('ui-draggable-dragging')) {
                  if (options.eventClick) {
                     var res = options.eventClick.call(this, event, ev);
                     if (res === false) {
                        return false;
                     }
                  }
                  if (event.url) {
                     window.location.href = event.url;
                  }
               }
            });
            if (options.eventMouseover) {
               element.mouseover(function(ev) {
                  options.eventMouseover.call(this, event, ev);
               });
            }
            if (options.eventMouseout) {
               element.mouseout(function(ev) {
                  options.eventMouseout.call(this, event, ev);
               });
            }
            if (typeof event.draggable != 'undefined') {
               if (event.draggable) {
                  draggableEvent(event, element);
               }
            }
            else if (options.draggable) {
               draggableEvent(event, element);
            }
            eventElements.push([event, element]);
         }


         //
         // Remove all event segments from DOM
         //

         function clearEventElements() {
            for (var i = 0; i < eventElements.length; i++) {
               eventElements[i][1].remove();
            }
            eventElements = [];
         }

         // PHUC CODE CHANGE: ADD Function clearHolidayElements();
         function clearHolidayElements() {
            $('.day').each(function(index) {
               $(this).removeClass('specialdays');
            });
         }


         /*******************************************************************/
         //
         //    Drag & Drop    (and cell-coordinate stuff)
         //
         /*******************************************************************/


         //
         // Attach jQuery UI draggable
         //

         var dragStartTD, dragTD;
         var dayOverlay;

         function draggableEvent(event, element) {
            element.draggable({
               zIndex: 4,
               delay: 50,
               opacity: options.eventDragOpacity,
               revertDuration: options.eventRevertDuration,
               start: function(ev, ui) {
                  // hide other elements with same event
                  for (var i = 0; i < eventElements.length; i++) {
                     var x = eventElements[i];
                     var xevent = x[0];
                     if (x[1].get(0) != this && (xevent == event ||
                             typeof xevent.id != 'undefined' && xevent.id == event.id)) {
                        x[1].hide();
                     }
                  }
                  if (!dayOverlay) {
                     dayOverlay =
                             $("<div class='over-day' style='position:absolute;z-index:2' />")
                                     .appendTo(monthElement);
                  }
                  buildDayGrid();
                  dragTD = dragStartTD = null;
                  eventDrag(this, ev, ui);
                  if (options.eventDragStart) {
                     options.eventDragStart.call(this, event, ev, ui);
                  }
               },
               drag: function(ev, ui) {
                  eventDrag(this, ev, ui);
               },
               stop: function(ev, ui) {
                  if (!dragTD || dragTD == dragStartTD) {
                     // show all events
                     for (var i = 0; i < eventElements.length; i++) {
                        eventElements[i][1].show();
                     }
                  } else {
                     var delta = dayDelta(dragStartTD, dragTD);
                     for (var i = 0; i < events.length; i++) {
                        if (event == events[i] || typeof event.id != 'undefined' && event.id == events[i].id) {
                           addDays(events[i].start, delta, true);
                           addDays(events[i].end, delta, true);
                           events[i]._start = cloneDate(events[i].start);
                        }
                     }
                     if (options.eventDrop) {
                        options.eventDrop.call(this, event, delta, ev, ui);
                     }
                     clearEventElements();
                     renderEvents();
                  }
                  dayOverlay.hide();
                  if (options.eventDragStop) {
                     options.eventDragStop.call(this, event, ev, ui);
                  }
               }
            });
         }


         //
         // Called DURING dragging, on every mouse move
         //

         function eventDrag(node, ev, ui) {
            var oldTD = dragTD;
            dragTD = dayTD(ev.pageX, ev.pageY);
            if (!dragStartTD) {
               dragStartTD = dragTD;
            }
            if (dragTD != oldTD) {
               if (dragTD) {
                  $(node).draggable('option', 'revert', dragTD == dragStartTD);
                  dayOverlay.css({
                     top: currTDY,
                     left: currTDX,
                     width: currTDW,
                     height: currTDH,
                     display: 'block'
                  });
               } else {
                  $(node).draggable('option', 'revert', true);
                  dayOverlay.hide();
               }
            }
         }


         //
         // Record positions & dimensions of each TD
         //

         var dayX, dayY, dayX0, dayY0;
         var currTD, currR, currC;
         var currTDX, currTDY, currTDW, currTDH;

         function buildDayGrid() {
            var tr, td, o = monthElement.offset();
            dayX0 = o.left;
            dayY0 = o.top;
            dayY = [];
            tbody.find('tr').each(function() {
               tr = $(this);
               dayY.push(tr.position().top +
                       (trTopBug ? tbody.position().top : 0));
            });
            dayY.push(dayY[dayY.length - 1] + tr.height());
            dayX = [];
            tr.find('td').each(function() {
               td = $(this);
               dayX.push(td.position().left);
            });
            dayX.push(dayX[dayX.length - 1] + td.width());
            currTD = null;
         }

         //
         // Returns TD underneath coordinate (optimized)
         //

         function dayTD(x, y) {
            var r = -1, c = -1;
            var rmax = dayY.length - 1, cmax = dayX.length - 1;
            while (r < rmax && y > dayY0 + dayY[r + 1]) {
               r++;
            }
            while (c < cmax && x > dayX0 + dayX[c + 1]) {
               c++;
            }
            if (r < 0 || r >= rmax || c < 0 || c >= cmax) {
               return currTD = null;
            }
            else if (!currTD || r != currR || c != currC) {
               currR = r;
               currC = c;
               currTD = tbody.find('tr:eq(' + r + ') td:eq(' + c + ')').get(0);
               currTDX = dayX[c];
               currTDY = dayY[r];
               currTDW = dayX[c + 1] - currTDX;
               currTDH = dayY[r + 1] - currTDY;
               return currTD;
            }
            return currTD;
         }

         //
         // Get a TD's date
         //

         function dayDate(td) {
            var i, trs = tbody.get(0).getElementsByTagName('tr');
            for (i = 0; i < trs.length; i++) {
               var tr = trs[i];
               for (var j = 0; j < 7; j++) {
                  if (tr.childNodes[j] == td) {
                     var d = cloneDate(start);
                     return addDays(d, i * 7 + j * dis + dit);
                  }
               }
            }
         }

         //
         // Return the # of days between 2 TD's
         //

         function dayDelta(td1, td2) {
            var i1, i2, trs = tbody.get(0).getElementsByTagName('tr');
            for (var i = 0; i < trs.length; i++) {
               var tr = trs[i];
               for (var j = 0; j < 7; j++) {
                  var td = tr.childNodes[j];
                  if (td == td1) {
                     i1 = i * 7 + j * dis + dit;
                  }
                  if (td == td2) {
                     i2 = i * 7 + j * dis + dit;
                  }
               }
            }
            return i2 - i1;
         }


         /*******************************************************************/
         //
         //    Event Sources & Fetching
         //
         /*******************************************************************/


         //
         // Fetch from ALL sources. Clear 'events' array and populate
         //

         function fetchEvents(callback) {
            events = [];
            if (eventSources.length > 0) {
               var queued = eventSources.length;
               var sourceDone = function() {
                  if (--queued == 0) {
                     popLoading();
                     if (callback) {
                        callback(events);
                     }
                  }
               };
               pushLoading();
               for (var i = 0; i < eventSources.length; i++) {
                  fetchEventSource(eventSources[i], sourceDone);
               }
            }
         }


         //
         // Fetch from a particular source. Append to the 'events' array
         //

         function fetchEventSource(src, callback) {
            var y = date.getFullYear();
            var m = date.getMonth();
            var reportEvents = function(a) {
               if (date.getFullYear() == y && date.getMonth() == m) {
                  for (var i = 0; i < a.length; i++) {
                     normalizeEvent(a[i]);
                     a[i].source = src;
                  }
                  events = events.concat(a);
               }
               if (callback) {
                  callback(a);
               }
            };
            if (typeof src == 'string') {
               var params = {};
               params[options.startParam || 'start'] = Math.round(start.getTime() / 1000);
               params[options.endParam || 'end'] = Math.round(end.getTime() / 1000);
               params[options.cacheParam || '_'] = (new Date()).getTime();
               $.getJSON(src, params, reportEvents);
            }
            else if ($.isFunction(src)) {
               src(start, end, reportEvents);
            }
            else {
               reportEvents(src);
            }
         }


         //
         // methods for reporting loading state
         //

         var loadingLevel = 0;

         function pushLoading() {
            if (!loadingLevel++ && options.loading) {
               options.loading(true);
            }
         }

         function popLoading() {
            if (! --loadingLevel && options.loading) {
               options.loading(false);
            }
         }


         /*******************************************************************/
         //
         //    Begin "Main" Execution
         //
         /*******************************************************************/

         var e = $(this);
         var _e = this;
         var resizeID = 0;
         $(window).resize(function() {   // re-render table on window resize
            if (!ignoreResizes) {
               var rid = ++resizeID;   // add a delay
               setTimeout(function() {
                  if (rid == resizeID) {
                     // if calendar is visible
                     if (e.css('display') != 'none') {
                        // if the month width changed
                        if (monthElement.width() != monthElementWidth) {
                           clearEventElements();
                           setCellSizes();
                           _renderEvents();
                           if (options.resize) {
                              options.resize.call(_e);
                           }
                        }
                     }
                  }
               }, 200);
            }
         });


         // let's begin...
         if (e.css('display') != 'none') {
            render();
         }

      });

      return this;
   };


   /***************************************************************************/
   //
   //      Utilities
   //
   /***************************************************************************/


   //
   // event utils
   //

   function normalizeEvent(event) {
      if (event.date) {
         event.start = event.date;
         delete event.date;
      }
      event.start = $.fullCalendar.parseDate(event.start);
      event._start = cloneDate(event.start);
      event.end = $.fullCalendar.parseDate(event.end);
      if (!event.end || event.end <= event.start) {
         event.end = addDays(cloneDate(event.start), 1);
      }
      return event;
   }

   function segCmp(a, b) {
      return (b.msLength - a.msLength) * 100 + (a.event.start - b.event.start);
   }


   //
   // string utils
   //

   function zeroPad(n) {
      return (n < 10 ? '0' : '') + n;
   }


   //
   // date utils
   //

   function addMonths(d, n, keepTime) {
      d.setMonth(d.getMonth() + n);
      if (keepTime) {
         return d;
      }
      return clearTime(d);
   }

   function addYears(d, n, keepTime) {
      d.setFullYear(d.getFullYear() + n);
      if (keepTime) {
         return d;
      }
      return clearTime(d);
   }

   function addDays(d, n, keepTime) {
      d.setDate(d.getDate() + n);
      if (keepTime) {
         return d;
      }
      return clearTime(d);
   }

   function clearTime(d) {
      d.setHours(0);
      d.setMinutes(0);
      d.setSeconds(0);
      d.setMilliseconds(0);
      return d;
   }

   function cloneDate(d) {
      return new Date(+d);
   }


   //
   // globally accessible date formatting & parsing
   //

   $.fullCalendar = {

      monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
      monthAbbrevs: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
      dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
      dayAbbrevs: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],

      formatDate: function(d, format) {
         var f = $.fullCalendar.dateFormatters;
         var s = '';
         for (var i = 0; i < format.length; i++) {
            var c = format.charAt(i);
            if (f[c]) {
               s += f[c](d);
            } else {
               s += c;
            }
         }
         return s;
      },

      dateFormatters: {
         'a': function(d) {
            return d.getHours() < 12 ? 'am' : 'pm';
         },
         'A': function(d) {
            return d.getHours() < 12 ? 'AM' : 'PM';
         },
         'x': function(d) {
            return d.getHours() < 12 ? 'a' : 'p';
         },
         'X': function(d) {
            return d.getHours() < 12 ? 'A' : 'P';
         },
         'g': function(d) {
            return d.getHours() % 12 || 12;
         },
         'G': function(d) {
            return d.getHours();
         },
         'h': function(d) {
            return zeroPad(d.getHours() % 12 || 12);
         },
         'H': function(d) {
            return zeroPad(d.getHours());
         },
         'i': function(d) {
            return zeroPad(d.getMinutes());
         },
         'F': function(d) {
            return $.fullCalendar.monthNames[d.getMonth()];
         },
         'm': function(d) {
            return zeroPad(d.getMonth() + 1);
         },
         'M': function(d) {
            return $.fullCalendar.monthAbbrevs[d.getMonth()];
         },
         'n': function(d) {
            return d.getMonth() + 1;
         },
         'Y': function(d) {
            return d.getFullYear();
         },
         'y': function(d) {
            return (d.getFullYear() + '').substring(2);
         },
         'c': function(d) {
            // ISO8601. derived from http://delete.me.uk/2005/03/iso8601.html
            return d.getUTCFullYear() +
                    "-" + zeroPad(d.getUTCMonth() + 1) +
                    "-" + zeroPad(d.getUTCDate()) +
                    "T" + zeroPad(d.getUTCHours()) +
                    ":" + zeroPad(d.getUTCMinutes()) +
                    ":" + zeroPad(d.getUTCSeconds()) +
                    "Z";
         }
      },

      parseDate: function(s) {
         if (typeof s == 'object') {
            return s;
         } // already a Date object
         if (typeof s == 'undefined') {
            return null;
         }
         if (typeof s == 'number') {
            return new Date(s * 1000);
         }
         return $.fullCalendar.parseISO8601(s, true) ||
                 Date.parse(s) ||
                 new Date(parseInt(s) * 1000);
      },

      parseISO8601: function(s, ignoreTimezone) {
         // derived from http://delete.me.uk/2005/03/iso8601.html
         var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
                 "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
                 "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
         var d = s.match(new RegExp(regexp));
         if (!d) {
            return null;
         }
         var offset = 0;
         var date = new Date(d[1], 0, 1);
         if (d[3]) {
            date.setMonth(d[3] - 1);
         }
         if (d[5]) {
            date.setDate(d[5]);
         }
         if (d[7]) {
            date.setHours(d[7]);
         }
         if (d[8]) {
            date.setMinutes(d[8]);
         }
         if (d[10]) {
            date.setSeconds(d[10]);
         }
         if (d[12]) {
            date.setMilliseconds(Number("0." + d[12]) * 1000);
         }
         if (!ignoreTimezone) {
            if (d[14]) {
               offset = (Number(d[16]) * 60) + Number(d[17]);
               offset *= ((d[15] == '-') ? 1 : -1);
            }
            offset -= date.getTimezoneOffset();
         }
         return new Date(Number(date) + (offset * 60 * 1000));
      }

   };

   // additional FullCalendar "extensions" should be attached to $.fullCalendar

})(jQuery);